﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.TextMining.NamedEntities
{
    /// <summary>
    /// 
    /// </summary>
    public partial class OrganizationEncodingEditor : Form, IComponentEditor
    {
        private object _ActivityNode;
        private OrganizationEncodingComponent _OrgEncoder;
        private Dictionary<string, Dictionary<string, int>> _EntityFreqs;

        /// <summary>
        /// 
        /// </summary>
        public OrganizationEncodingEditor()
        {
            InitializeComponent();
        }

        private void OrganizationEncodingEditor_Load(object sender, EventArgs e)
        {
            this._EntityFreqs=new Dictionary<string, Dictionary<string, int>>();
            string fileContent = Properties.Resources.EntityFreqs;
            string[] lines = fileContent.Split(new char[] {'\n', 'r'});
            foreach(string line in lines)
            {
                if(line.Trim().Length==0)
                    continue;
                string[] type_word_freq = line.Split(new char[] {','});
                if(type_word_freq.Length==3)
                {
                    string entityType = type_word_freq[0];
                    string word = type_word_freq[1];
                    int freq = int.Parse(type_word_freq[2]);
                    if(this._EntityFreqs.ContainsKey(entityType))
                    {
                        Dictionary<string,int> wordFreq=new Dictionary<string, int>();
                        if(!wordFreq.ContainsKey(word))
                            wordFreq.Add(word, freq);
                        this._EntityFreqs[entityType] = wordFreq;
                    }
                    else
                    {
                        Dictionary<string,int> wordFreq=new Dictionary<string, int>();
                        wordFreq.Add(word,freq);
                        this._EntityFreqs.Add(entityType,wordFreq);
                    }
                }
            }
            this.cbo_EntityType.Items.Clear();
            if(this._EntityFreqs !=null && this._EntityFreqs.Count>0)
            {
                foreach (string entityType in this._EntityFreqs.Keys)
                    this.cbo_EntityType.Items.Add(entityType);
            }
        }

        #region Implementation of IComponentEditor

        public event UpdateComponentSettings UpdateComponentSettingEvent;

        /// <summary></summary>
        public object OwnerActivityNode
        {
            get { return _ActivityNode; }
            set { _ActivityNode = value; }
        }

        /// <summary></summary>
        public Type WorkflowComponentType
        {
            get { return typeof (OrganizationEncodingComponent); }
        }

        /// <summary></summary>
        public void LoadSettings(GlobalVariable[] globalVars, WorkflowComponentBase[] fromComponents, object activityNode, WorkflowComponentBase wfComponent)
        {
            this._ActivityNode = activityNode;
            this._OrgEncoder = (OrganizationEncodingComponent) wfComponent;
            OrganizationEncodingInstruction instruction = (OrganizationEncodingInstruction) this._OrgEncoder.Instruction;
            this.txt_ConnStr.Text = instruction.ConnStr;
            this.txt_Schema.Text = instruction.SchemaName;
            this.PopulateTables(instruction.ConnStr, instruction.SchemaName);
            this.SelectComboxValue(this.cbo_Table, instruction.TableName);
            this.rt_SQL.Text = instruction.Sql;
            this.PopulateTableFields(instruction.ConnStr, instruction.SchemaName, instruction.TableName, instruction.Sql);
            this.SelectComboxValue(this.cbo_PKField, instruction.PKField);
            this.SelectComboxValue(this.cbo_OrgNameField, instruction.OrgNameField);

            this.dv_Patterns.Rows.Clear();
            if(instruction.OrgEntityPatterns !=null && instruction.OrgEntityPatterns.Count>0)
            {
                foreach(string entityType in instruction.OrgEntityPatterns.Keys)
                {
                    double weight = 0;
                    if (instruction.OrgEntityWeights != null && instruction.OrgEntityWeights.ContainsKey(entityType))
                        weight = instruction.OrgEntityWeights[entityType];
                    double penalty = 0;
                    if (instruction.OrgEntityPenalties != null && instruction.OrgEntityPenalties.ContainsKey(entityType))
                        penalty = instruction.OrgEntityPenalties[entityType];
                    foreach(string pattern in instruction.OrgEntityPatterns[entityType])
                    {
                        DataGridViewRow dr = new DataGridViewRow();
                        DataGridViewTextBoxCell cellEntity = new DataGridViewTextBoxCell();
                        cellEntity.Value = entityType;
                        dr.Cells.Add(cellEntity);
                        DataGridViewTextBoxCell cellPattern = new DataGridViewTextBoxCell();
                        cellPattern.Value = pattern;
                        dr.Cells.Add(cellPattern);
                        DataGridViewTextBoxCell cellWeight = new DataGridViewTextBoxCell();
                        cellWeight.Value = weight;
                        dr.Cells.Add(cellWeight);
                        DataGridViewTextBoxCell cellPenalty = new DataGridViewTextBoxCell();
                        cellPenalty.Value = penalty;
                        dr.Cells.Add(cellPenalty);
                        this.dv_Patterns.Rows.Add(dr);
                    }
                }
            }

            this.num_LinkThreshold.Value = (decimal) instruction.LinkThreshold;
            this.txt_OutputTable.Text = instruction.OutputTable;
        }

        private void PopulateTableFields(string connStr, string schemaName, string tableName, string sql)
        {
            TableColumn[] cols = null;
            if (!string.IsNullOrEmpty(sql))
                cols = DbUtil.GetTableColumns(DataProviderType.MSSQL, connStr, sql);
            else
                cols = DbUtil.GetTableColumns(DataProviderType.MSSQL, connStr, schemaName, tableName);
            this.cbo_PKField.Items.Clear();
            this.cbo_OrgNameField.Items.Clear();
            if(cols !=null && cols.Length>0)
            {
                foreach(TableColumn col in cols)
                {
                    this.cbo_PKField.Items.Add(col.ColumnName);
                    this.cbo_OrgNameField.Items.Add(col.ColumnName);
                }
            }
        }

        private void SelectComboxValue(ComboBox comboBox, string name)
        {
            if(comboBox.Items.Count>0 && !string.IsNullOrEmpty(name))
            {
                for(int i=0;i<comboBox.Items.Count;i++)
                {
                    if(comboBox.Items[i].ToString().ToLower()==name.ToLower())
                    {
                        comboBox.SelectedIndex = i;
                        break;
                    }
                }
            }
        }

        private void PopulateTables(string connStr, string schemaName)
        {
            this.cbo_Table.Items.Clear();
            string[] tblNames = DbUtil.GetTableNames(DataProviderType.MSSQL, schemaName, connStr);
            if(tblNames !=null && tblNames.Length>0)
            {
                foreach(string tblName in tblNames)
                {
                    this.cbo_Table.Items.Add(tblName);
                }
            }
        }

        /// <summary></summary>
        public void SaveSettings()
        {
            OrganizationEncodingInstruction instruction = (OrganizationEncodingInstruction) this._OrgEncoder.Instruction;
            instruction.ConnStr = this.txt_ConnStr.Text;
            instruction.SchemaName = this.txt_Schema.Text;
            instruction.TableName = this.cbo_Table.Text;
            instruction.Sql = this.rt_SQL.Text;
            instruction.PKField = this.cbo_PKField.Text;
            instruction.OrgNameField = this.cbo_OrgNameField.Text;
            instruction.OrgEntityPatterns=new Dictionary<string, List<string>>();
            instruction.OrgEntityWeights=new Dictionary<string, double>();
            instruction.OrgEntityPenalties=new Dictionary<string, double>();
            foreach(DataGridViewRow dr in this.dv_Patterns.Rows)
            {
                if(!dr.IsNewRow && dr.Cells[0].Value!=null && dr.Cells[1].Value!=null)
                {
                    string entityType = dr.Cells[0].Value.ToString();
                    string pattern = dr.Cells[1].Value.ToString();
                    double weight = double.Parse(dr.Cells[2].Value.ToString());
                    double penalty = double.Parse(dr.Cells[3].Value.ToString());
                    if(!instruction.OrgEntityPatterns.ContainsKey(entityType))
                    {
                        List<string> patterns=new List<string>();
                        patterns.Add(pattern);
                        instruction.OrgEntityPatterns.Add(entityType,patterns);
                        instruction.OrgEntityPenalties.Add(entityType,penalty);
                        instruction.OrgEntityWeights.Add(entityType,weight);
                    }
                    else
                    {
                        List<string> patterns = instruction.OrgEntityPatterns[entityType];
                        patterns.Add(pattern);
                        instruction.OrgEntityPatterns[entityType] = patterns;
                    }
                }
            }

            instruction.LinkThreshold = (double) this.num_LinkThreshold.Value;
            instruction.OutputTable = this.txt_OutputTable.Text;
            this._OrgEncoder.Instruction = instruction;
        }

        /// <summary></summary>
        public TestResult Test()
        {
            throw new System.NotImplementedException();
        }

        #endregion

        private void cbo_EntityType_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.lb_Words.Items.Clear();
            if(this.cbo_EntityType.SelectedIndex>=0)
            {
                string entityType = this.cbo_EntityType.SelectedItem.ToString();
                if(this._EntityFreqs !=null && this._EntityFreqs.ContainsKey(entityType))
                {
                    Dictionary<string, int> wordFreq = this._EntityFreqs[entityType];
                    foreach(string word in wordFreq.Keys)
                    {
                        this.lb_Words.Items.Add(word);
                    }
                }
            }
        }

        private void btn_AddPatterns_Click(object sender, EventArgs e)
        {
            if(this.lb_Words.SelectedItems.Count>0 && 
                this.cbo_EntityType.SelectedIndex>=0 && 
                !string.IsNullOrEmpty(this.txt_Patterns.Text))
            {
                string patternType = this.cbo_EntityType.SelectedItem.ToString();
                string patternTemplate = this.txt_Patterns.Text;
                double weight = 1.0;
                double penalty = 0.0;
                List<string> words=new List<string>();
                foreach(int selectedIdx in this.lb_Words.SelectedIndices)
                {
                    words.Add(this.lb_Words.Items[selectedIdx].ToString());
                }
                List<string> patterns=new List<string>();
                if(patternTemplate.IndexOf("{0}")>=0)
                {
                    foreach(string word in words)
                    {
                        string pat = string.Format(patternTemplate, word);
                        patterns.Add(pat);
                    }
                }
                else
                {
                    foreach(string word in words)
                    {
                        patterns.Add(word);
                    }
                }
                foreach(string pattern in patterns)
                {
                    DataGridViewRow dr = new DataGridViewRow();
                    DataGridViewTextBoxCell cellEntity=new DataGridViewTextBoxCell();
                    cellEntity.Value = patternType;
                    dr.Cells.Add(cellEntity);
                    DataGridViewTextBoxCell cellPattern=new DataGridViewTextBoxCell();
                    cellPattern.Value = pattern;
                    dr.Cells.Add(cellPattern);
                    DataGridViewTextBoxCell cellWeight=new DataGridViewTextBoxCell();
                    cellWeight.Value = weight;
                    dr.Cells.Add(cellWeight);
                    DataGridViewTextBoxCell cellPenalty=new DataGridViewTextBoxCell();
                    cellPenalty.Value = penalty;
                    dr.Cells.Add(cellPenalty);
                    this.dv_Patterns.Rows.Add(dr);
                }
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            this.SaveSettings();
            if (this.UpdateComponentSettingEvent != null)
                this.UpdateComponentSettingEvent(this._ActivityNode, this._OrgEncoder);
            this.Close();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
